package com.newx.test.open.tcp5;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Classname MCUServer
 * @Description TODO 服务端代码（Java服务端）
 * @Date 2025/1/8 8:30
 * @Created by yxl
 */
public class MCUServer {
    public static final int BUFFER_SIZE = 1024; // 增大缓冲区大小以提高传输效率
    public static final int TIMEOUT_MS = 5000;  // 确认超时时间（毫秒）

    private static final ExecutorService threadPool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
        String host = "127.0.0.1"; // 本地回环地址
        int port = 5000; // 监听端口

        try (ServerSocket serverSocket = new ServerSocket(port)) {
            System.out.println("Java服务端正在监听 " + host + ":" + port + "...");

            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("收到客户端连接请求");

                // 使用线程池处理每个客户端连接
                threadPool.submit(() -> handleClient(clientSocket));
            }
        } catch (IOException e) {
            System.err.println("无法绑定到端口: " + e.getMessage());
        } finally {
            threadPool.shutdown();
        }
    }

    private static void handleClient(Socket clientSocket) {
        try {
            // 设置读取超时
            clientSocket.setSoTimeout(TIMEOUT_MS);

            try (
                    BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                    DataOutputStream outStream = new DataOutputStream(clientSocket.getOutputStream())
            ) {
                System.out.println("处理来自 " + clientSocket.getInetAddress() + " 的连接");

                // 等待客户端发送消息
                String message;
                while ((message = in.readLine()) != null) {
                    System.out.println("收到客户端消息: " + message);

                    // 根据接收到的消息准备发送文件
                    if ("Request file".equalsIgnoreCase(message)) {
                        System.out.println("等待用户确认发送文件...");

                        // 直接发送文件
                        sendFile(outStream, in, "F:\\Desktop\\test.bin");
                        break;
                    } else {
                        outStream.writeUTF("Unknown command");
                        outStream.flush();
                    }
                }
            }
        } catch (SocketTimeoutException e) {
            System.err.println("客户端连接超时: " + e.getMessage());
        } catch (IOException e) {
            System.err.println("处理客户端时发生IO异常: " + e.getMessage());
        }
    }

    private static void sendFile(DataOutputStream outStream, BufferedReader in, String filePath) throws IOException {
        Path path = Paths.get(filePath);
        if (!Files.exists(path)) {
            outStream.writeUTF("File not found: " + filePath);
            outStream.flush();
            return;
        }

        File file = path.toFile();
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead;

            // 发送文件名和文件大小
            outStream.writeUTF(file.getName());
            outStream.writeLong(file.length());
            outStream.flush();

            // 发送文件内容，分包处理
            int packetNumber = 0;
            while ((bytesRead = fis.read(buffer)) != -1) {
                // 发送数据包
                outStream.writeInt(packetNumber); // 数据包序号
                outStream.writeInt(bytesRead);    // 数据长度
                outStream.write(buffer, 0, bytesRead);
                outStream.flush();

                // 等待确认
                long startTime = System.currentTimeMillis();
                boolean ackReceived = false;
                while (!ackReceived && (System.currentTimeMillis() - startTime < TIMEOUT_MS)) {
                    String ack = in.readLine();
                    if (ack != null && ack.equals("ACK " + packetNumber)) {
                        ackReceived = true;
                        System.out.println("收到确认，继续发送下一个数据包 " + packetNumber);
                        break;
                    }
                }

                if (!ackReceived) {
                    System.out.println("未收到确认，重传数据包 " + packetNumber);
                    continue; // 重试当前数据包，而不是回退文件指针
                }

                packetNumber++;
            }

            System.out.println("文件发送完成: " + filePath);
        } catch (IOException e) {
            System.err.println("文件传输过程中发生IO异常: " + e.getMessage());
            throw e;
        }
    }
}
